﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace legend
{
    public class MemoryUtil64
    {
        [DllImport("user32.dll")]//查找窗口
        public static extern int FindWindow(
                                            string strClassName,    //窗口类名
                                            string strWindowName    //窗口标题
        );

        [DllImport("user32.dll")]//在窗口列表中寻找与指定条件相符的第一个子窗口
        public static extern int FindWindowEx(
                                              int hwndParent, // handle to parent window
                                                int hwndChildAfter, // handle to child window
                                              string className, //窗口类名            
                                              string windowName // 窗口标题
        );
        [DllImport("user32.dll")]//找出某个窗口的创建者(线程或进程),返回创建者的标志符
        public static extern int GetWindowThreadProcessId(int hwnd, out int processId);
        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern Boolean ReadProcessMemory(HandleRef hProcess, Int64 lpBaseAddress, [In, Out] Byte[] lpBuffer, Int64 nSize, Int64 lpNumberOfBytesRead);

        [DllImport("user32.dll")]
        public static extern Boolean SetCursorPos(int x, int y);

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern Boolean WriteProcessMemory(HandleRef hProcess, Int64 lpBaseAddress, Byte[] lpBuffer, Int64 nSize, Int64 lpNumberOfBytesWritten);

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern Boolean VirtualProtectEx(HandleRef hProcess, Int64 lpAddress, Int64 dwSize, UInt32 flNewProtect, out UInt32 lpflOldProtect);

        [DllImport("kernel32.dll")]
        public static extern Int64 VirtualQueryEx(HandleRef hProcess, Int64 lpAddress, out MEMORY_BASIC_INFORMATION64 lpBuffer, Int64 dwLength);

        //详见 https://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx 备注
        [StructLayout(LayoutKind.Sequential, Pack = 16)]
        public struct MEMORY_BASIC_INFORMATION64
        {
            public Int64 BaseAddress;
            public Int64 AllocationBase;
            public UInt32 AllocationProtect;
            public UInt32 __alignment1;
            public Int64 RegionSize;
            public UInt32 State;
            public UInt32 Protect;
            public UInt32 Type;
            public UInt32 __alignment2;

        }

        public const Int64 MEMORY_BASIC_INFORMATION64_SIZE = 48;

        //https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa366786(v=vs.85).aspx
        public const UInt32 PAGE_EXECUTE_READ = 0x20;
        public const UInt32 PAGE_EXECUTE_READWRITE = 0x40;

        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx
        public const UInt32 MEM_COMMIT = 0x1000;

        //全局变量，表示游戏进程
        public Process GameProcess = null;

        public static Byte[] ReadBytes(HandleRef hr, Int64 address, Int64 length)
        {
            var buffer = new Byte[length];
            ReadProcessMemory(hr, address, buffer, length, 0);
            return buffer;
        }

        public void WriteBytes(Int64 address, Byte[] data)
        {
            WriteProcessMemory(new HandleRef(GameProcess, GameProcess.Handle), address, data, data.LongLength, 0);
        }

        public void WriteBytes(Int64 address, Byte[] data, Int32 length)
        {
            WriteProcessMemory(new HandleRef(GameProcess, GameProcess.Handle), address, data, length, 0);
        }

        #region Sunday Quick-Search算法的C#实现

        public static Int32[] FlagBuffer = new Int32[256];

        public static Int32 QSIndexOf(Byte[] source, Byte[] pattern)
        {

            if (source.Length < pattern.Length)
            {
                return -1;
            }

            var sLength = source.Length;
            var pLength = pattern.Length;
            var pMaxIndex = pLength - 1;
            var startIndex = 0;
            var endPos = sLength - pLength;
            var badMov = pLength + 1;

            for (Int32 i = 0; i < 256; i++)
            {
                FlagBuffer[i] = badMov;

            }
            for (int i = 0; i <= pMaxIndex; i++)
            {
                FlagBuffer[pattern[i]] = pLength - i;
            }

            Int32 pIndex, step, result = -1;

            while (startIndex <= endPos)
            {
                for (pIndex = 0; pIndex <= pMaxIndex && source[startIndex + pIndex] == pattern[pIndex]; pIndex++)
                {
                    if (pIndex == pMaxIndex)
                    {
                        result = startIndex;
                    }
                }
                if (result > -1) break;
                step = startIndex + pLength;
                if (step >= sLength) break;
                startIndex += FlagBuffer[source[step]];
            }
            return result;
        }

        #endregion
    }
}
